#ifndef TASK_MUTEX_H
#define TASK_MUTEX_H

#include "copy/noncopyable.h"
#include "Thread.h"

#include <cassert>

/**
 * 基本的锁, 对需要加锁的资源需要在对应的类中声明对应的成员对象
 */
class MutexLock : muduo::noncopyable {
public:
    MutexLock() : holder_(0){
        pthread_mutex_init(&mutex_, nullptr);
        // 初始化线程锁
    }

    virtual ~MutexLock() {
        assert(holder_ == 0);
        pthread_mutex_destroy(&mutex_);
    }

    bool isLockedByThisThread(){
        return holder_ == Thread::getTid();
    }

    void assertLocked(){
       assert(isLockedByThisThread());
    }

    void lock(){
        pthread_mutex_lock(&mutex_);
         holder_ = Thread::getTid();
        // 先加锁再设置对应的线程, 交换在并发环境可能会导致重复设置
    }

    void unlock(){
        holder_ = 0;
        pthread_mutex_unlock(&mutex_);
    }

    pthread_mutex_t  * getPthreadMutex(){
        return & mutex_;
    }

private:
    pthread_mutex_t mutex_;
    pid_t holder_;
};

/**
 * 互斥锁对象, 初始化使用对象资源中的MutexLock对象来加锁
 * 使用构造和析构来加锁和解锁
 */
class MutexLockGuard : muduo::noncopyable{
public:
    explicit MutexLockGuard(MutexLock & mutex) : mutex_(mutex){
        mutex.lock();
    }

    virtual ~MutexLockGuard() {
        mutex_.unlock();
    }

private:
    MutexLock & mutex_;
};

#define MutexLockGuard(x) static_assert(flase, "missing mutex guard var name")
// 防止在使用的时候产生临时变量快速产生又释放了锁

/**
 * 条件变量, 基于锁来定义的
 */
class Condition : muduo::noncopyable{
public:
    explicit Condition(MutexLock & mutex) : mutex_(mutex){
        pthread_cond_init(&pcond_, nullptr);
    }

    virtual ~Condition() {
        pthread_cond_destroy(&pcond_);
    }

    void wait(){
        pthread_cond_wait(&pcond_, mutex_.getPthreadMutex());
    }

    void notify(){
        pthread_cond_signal(&pcond_);
    }

    void notifyAll(){
        pthread_cond_broadcast(&pcond_);
    }

private:
    MutexLock & mutex_;
    pthread_cond_t pcond_;
};

#endif //TASK_MUTEX_H
